
#include <usart_extern.h>
#include "debug_button_extern.h"

struct ButtonHandler button0, button1, button2,button3;

void kernel_button_slow_tick_1ms() {
    handleButtons();
}
void onGPIOSwap_0(GPIO_PinState state) {

    if (state == GPIO_PIN_SET) {
        button0.button_latest_state = GPIO_PIN_RESET;
    } else {
        button0.button_latest_state = GPIO_PIN_SET;
    }
}

void onGPIOSwap_1(GPIO_PinState state) {
    if (state == GPIO_PIN_SET) {
        button1.button_latest_state = GPIO_PIN_RESET;
    } else {
        button1.button_latest_state = GPIO_PIN_SET;
    }
}

void onGPIOSwap_2(GPIO_PinState state) {
    if (state == GPIO_PIN_SET) {
        button2.button_latest_state = GPIO_PIN_RESET;
    } else {
        button2.button_latest_state = GPIO_PIN_SET;
    }
}

void onGPIOSwap_3(GPIO_PinState state) {
    if (state == GPIO_PIN_SET) {
        button3.button_latest_state = GPIO_PIN_RESET;
    } else {
        button3.button_latest_state = GPIO_PIN_SET;
    }
}

void button_init() {
    button0.buttonid = 0;
    button1.buttonid = 1;
    button2.buttonid = 2;
    button3.buttonid = 3;
    initButton(&button3);
    initButton(&button2);
    initButton(&button1);
    initButton(&button0);
}

void handleButtons() {
    handleButtonTick(&button3);
    handleButtonTick(&button2);
    handleButtonTick(&button1);
    handleButtonTick(&button0);
}

void initButton(struct ButtonHandler *handle) {
    (*handle).button_isPressed = GPIO_PIN_RESET;
    (*handle).button_latest_state = GPIO_PIN_RESET;
    (*handle).button_listen_enable = 0;
    (*handle).button_cycle_listen = 0;
    (*handle).button_hold_callback_reg = 0;
    (*handle).button_in_long_press_mode = 0;
    (*handle).button_hold_callback_enable = 0;
    (*handle).button_reg = 0;
}

void handleButtonTick(struct ButtonHandler *handle) {
    if ((*handle).button_listen_enable == 0) return;
    if ((*handle).button_isPressed != (*handle).button_latest_state) {
        if ((*handle).button_latest_state == GPIO_PIN_SET) {
            (*handle).button_isPressed = GPIO_PIN_SET;
            (*handle).button_start_mode = 1;
            (*handle).button_reg = 0;
            onPressDownCallback(handle);               //handle on press down
        } else {
            (*handle).button_isPressed = GPIO_PIN_RESET;
            (*handle).button_reg = 0;
            (*handle).button_hold_callback_reg = 0;
            (*handle).button_in_long_press_mode = 0;
            (*handle).button_start_mode = 0;
            onFreeCallback(handle);                     //handle on free.
            if (!(*handle).button_cycle_listen) {
                (*handle).button_listen_enable = 0;
                return;
            }
        }
    }
    if ((*handle).button_long_press_mode == 0 || (*handle).button_isPressed == GPIO_PIN_RESET) {
        return;
    }
    if ((*handle).button_start_mode) {
        (*handle).button_reg++;
        if ((*handle).button_time_limit <= (*handle).button_reg) {
            (*handle).button_in_long_press_mode = 1;
            (*handle).button_reg = 0;
            (*handle).button_start_mode = 0;
            onTimeReachCallback(handle);
        }
    }
    if ((*handle).button_hold_callback_enable && (*handle).button_in_long_press_mode) {
        (*handle).button_hold_callback_reg++;
        if ((*handle).button_hold_callback_reg == (*handle).button_hold_callback_cycle) {
            (*handle).button_hold_callback_reg = 0;
            onHoldCycleCallback(handle);
        }
    }

}


void onPressDownCallback(struct ButtonHandler *handle) {
    switch ((*handle).buttonid) {
        case 0:
            button0PressDownCallback();
            break;
        case 1:
            button1PressDownCallback();
            break;
        case 2:
            button2PressDownCallback();
            break;
        case 3:
            button3PressDownCallback();
            break;
    }
}

void onFreeCallback(struct ButtonHandler *handle) {
    switch ((*handle).buttonid) {
        case 0:
            button0FreeCallback();
            break;
        case 1:
            button1FreeCallback();
            break;
        case 2:
            button2FreeCallback();
            break;
        case 3:
            button3FreeCallback();
            break;
    }
}

void onTimeReachCallback(struct ButtonHandler *handle) {
    switch ((*handle).buttonid) {
        case 0:
            button0TimeReachCallback();
            break;
        case 1:
            button1TimeReachCallback();
            break;
        case 2:
            button2TimeReachCallback();
            break;
        case 3:
            button3TimeReachCallback();
            break;
    }
}

void onHoldCycleCallback(struct ButtonHandler *handle) {
    switch ((*handle).buttonid) {
        case 0:
            button0HoldCycleCallback();
            break;
        case 1:
            button1HoldCycleCallback();
            break;
        case 2:
            button2HoldCycleCallback();
            break;
        case 3:
            button3HoldCycleCallback();
            break;
    }
}

/**
 * register a button
 * @param buttonid button id
 * @param time long press time
 * @param mode is long press mode
 * @param cyclelisten is cycle listen
 * @param hold_callback hold on callback?
 */
void buttonRegister(uint8_t buttonid, uint16_t time, uint8_t mode, uint8_t cyclelisten, uint8_t hold_callback) {
    struct ButtonHandler *handle;
    switch (buttonid) {
        case 0:
            handle = &button0;
            break;
        case 1:
            handle = &button1;
            break;
        case 2:
            handle = &button2;
            break;
        case 3:
            handle = &button3;
            break;
        default:
            return;

    }
    (*handle).button_listen_enable = 1;
    (*handle).button_time_limit = time;
    (*handle).button_long_press_mode = mode;
    (*handle).button_cycle_listen = cyclelisten;
    if (hold_callback != 0) {
        (*handle).button_hold_callback_enable = 1;
        (*handle).button_hold_callback_cycle = hold_callback;
    } else {
        (*handle).button_hold_callback_enable = 0;
    }
}